package com.yonyou.wdt.job;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yonyou.wdt.dao.JobLogDao;
import com.yonyou.wdt.entity.OpenApiURLEnum;
import com.yonyou.wdt.entity.QueryDto;
import com.yonyou.wdt.job.config.BaseConfig;
import com.yonyou.wdt.model.JobLogModel;
import com.yonyou.wdt.service.CommonService;
import com.yonyou.wdt.service.YonsuiteService;
import com.yonyou.wdt.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ClassName YsProductToRedisJob
 * @Description 旺店通采购入库单数据同步至YonSuite采购入库
 * @Author HuangWb
 * @Date 2023/5/12 18:35
 * @Version 1.0
 */
@Component
public class WdtPurchaseInToYsPurchaseInJob extends BaseConfig {

    private final WdtConfigProperties configProperties;

    private static Logger logger = LoggerFactory.getLogger(WdtPurchaseInToYsPurchaseInJob.class);
    @Resource
    public JobLogDao jobLogDao;
    @Resource
    private YonsuiteService yonsuiteService;
    @Resource
    private CommonService commonService;

    @Autowired
    public WdtPurchaseInToYsPurchaseInJob(WdtConfigProperties configProperties) {
        this.configProperties = configProperties;
    }

    @XxlJob("WdtPurchaseInToYsPurchaseInJob")
    public ReturnT<String> wdtPurchaseInToYsPurchaseInJob(String params) throws Exception {
        String param = XxlJobHelper.getJobParam();
        Map<String, Object> map = new HashMap<>();
        if (param != null && !"".equals(param)) {
            List<String> timeRange = Arrays.asList(param.split("\\|"));
            if (timeRange.size() == 2) {
                map.put("Start", timeRange.get(0));
                map.put("End", timeRange.get(1));
            } else {
                map.put("stockin_no", timeRange.get(0));
            }
        } else {
            // 默认查询前一天的数据
            map.put("Start", DateUtils.getStartDateBy60m());
            map.put("End", DateUtils.getEndDateBy60m());
        }
        String dateStr = null;
        if (map.get("Start") != null && map.get("End") != null) {
            dateStr = map.get("Start").toString() + map.get("End").toString();
        }
        // 处理相关业务
        QueryDto dto = new QueryDto();
        dto.setTenantId(getYsTenantId());
        dto.setAppKey(getYsAppKey());
        dto.setAppSecret(getYsAppSecret());
        // 获取YS系统租户动态域名信息
        ReturnT<String> isReturn2 = getYsDynamicDomainName(dto);
        // 域名获取失败
        if (isReturn2 != null) return isReturn2;
        try {
            List<JSONObject> responseList = sendWdt(map);
            Integer successCount = 0;
            Integer failCount = 0;
            // 解析数据，组装YS请求参数
            if (!responseList.isEmpty()) {
                ArrayList<Map<String, Object>> ysSaveParamList = new ArrayList<>();
                for (int i = 0; i < responseList.size(); i++) {
                    JSONObject jsonObject = responseList.get(i);
                    //for (JSONObject jsonObject : responseList) {
                    Map<String, Object> ysSaveParam = assembleYsParams(jsonObject, dto);
                    if (ysSaveParam == null) {
                        failCount++;
                        continue;
                    }
                    JSONObject response = yonsuiteService.purchaseInSave(ysSaveParam, dto);
                    String wdtCode = JSONUtil.parseObj(ysSaveParam.get("data")).getStr("code");
                    if (null != response && "200".equals(response.getStr("code"))) {
                        successCount++;
                        logger.info("旺店通采购入库保存YS采购入库成功");
                        InsertLogger(wdtCode, "1", "旺店通采购入库" + wdtCode + "保存YS采购入库" + response.getJSONObject("data").getStr("code") + "成功");
                    } else {
                        failCount++;
                        logger.error("旺店通采购入库保存YS采购入库失败：{}", response.getOrDefault("message", ""));
                        InsertLogger(wdtCode, "0", "旺店通采购入库" + wdtCode + "保存YS采购入库失败" + response.getOrDefault("message", "").toString());
                    }
                    // 处理YS接口调用频率问题
                    // 调用YS接口保存数据
                    this.APICurrentLimiting(OpenApiURLEnum.PURCHASE_IN_SAVE, 39);
                    /*if (ysSaveParamList.size() >= 20) {
                        Thread.sleep(3000);
                    }*/
                }
                logger.info("当前时间段：{}至{} 需要同步到YS采购入库数据有：{}条", map.get("Start"), map.get("End"), responseList.size());
            }
            Thread.sleep(1000);
            InsertLogger(null, "0", "旺店通采购入库一共" + responseList.size() + "条,保存YS采购入库成功:" + successCount + "条，失败:" + failCount + "条。");
        } catch (Exception e) {
            logger.error("Error occurred", e);
            logger.error("旺店通采购入库同步YS采购入库失败，{}", e.getMessage());
            InsertLogger(null, "0", "旺店通采购入库同步YS采购入库失败" + e.getMessage());
            return ReturnT.FAIL;
        }
        logger.info("  --  旺店通采购入库同步YS采购入库任务执行完成  --  ");
        return ReturnT.SUCCESS;
    }

    /**
     * @return
     * @Author Huangwb
     * @Description 组装YS请求数据
     * @Date 14:34 2023/5/17
     * @Param
     **/
    private Map<String, Object> assembleYsParams(JSONObject jsonObject, QueryDto dto) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> body = new HashMap<>();
        String code = jsonObject.getStr("order_no");
        String orgId = "30";
        body.put("org", orgId);   // 库存组织
        body.put("code", code);   // 单据编码
        body.put("purchaseOrg", orgId); // 采购组织
        body.put("accountOrg", orgId);  // 会计主体
        body.put("inInvoiceOrg", orgId);// 收票组织
        body.put("vouchdate", jsonObject.getStr("created_time"));  // 单据日期
        // body.put("org_code", orgId);  //组织编码
        body.put("bustype", "A15001");  // 交易类型
        body.put("warehouse", jsonObject.getStr("warehouse_no"));  // 仓库
        String vendor = jsonObject.getStr("provider_no");
        body.put("vendor", vendor);  // 供应商
        body.put("currency", "CNY");  // 币种
        body.put("natCurrency", "CNY");  // 本币
        body.put("exchRateType", "01");  // 汇率类型
        body.put("exchRate", "1");  // 汇率
        body.put("_status", "Insert");  // 状态

        JSONArray details = jsonObject.getJSONArray("details_list");
        // ==========子表================
        JSONArray objects = new JSONArray();
        for (int j = 0; j < details.size(); j++) {
            JSONObject zb = details.getJSONObject(j);
            JSONObject redisPrJson = null;
            String product = String.valueOf(zb.get("goods_no"));  // 获取物料编码
            if (null != RedisUtils.get(dto.getTenantId() + ":product:" + product)) {
                redisPrJson = (JSONObject) RedisUtils.get(dto.getTenantId() + ":product:" + product);
            }
            if (redisPrJson == null) {
                // 保存同步错误日志，未找到对应物料档案信息
                commonService.proToRedis(product, dto);
                redisPrJson = (JSONObject) RedisUtils.get(dto.getTenantId() + ":product:" + product);
                if (redisPrJson == null) {
                    logger.error("存在未同步YS系统物料数据：{}，请同步后重试", product);
                    InsertLogger(code, "0", "存在未同步YS系统物料数据：" + product + "，请同步后重试");
                    return null;
                }
            }

            BigDecimal price = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
            Object object = RedisUtils.get(dto.getTenantId() + ":vsupplyCode:" + vendor + ":vmatSkuCode:" + product);
            /*if (object == null) {
                // 保存同步错误日志，未找到对应物料档案信息
                logger.error("存在未同步的价格目录YS系统供应商:{},物料数据：{}，请同步后重试", vendor, product);
                InsertLogger(null, "0", "存在未同步的价格目录YS系统供应商:" + vendor + ",物料数据：{" + product + "}，请同步后重试");
                return null;
            }*/
            if (object != null) {
                price = (BigDecimal) object;
            }
            BigDecimal qty = zb.getBigDecimal("num");
            // 金额
            BigDecimal saleAmount = qty.multiply(price).setScale(2, RoundingMode.HALF_UP);
            // 税率
            BigDecimal outTaxrate = redisPrJson.getBigDecimal("outTaxrate_Name") != null ? redisPrJson.getBigDecimal("outTaxrate_Name") : BigDecimal.valueOf(0);

            BigDecimal taxAmount = saleAmount.divide(outTaxrate.divide(new BigDecimal(100)).add(new BigDecimal(1)), 4, RoundingMode.HALF_UP).multiply(outTaxrate.divide(new BigDecimal(100))).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 无税金额
            BigDecimal noTaxSaleAmount = saleAmount.subtract(taxAmount);
            // 无税单价
            BigDecimal taxFreeUnitPrice = noTaxSaleAmount.divide(qty, 4, RoundingMode.HALF_UP);

            Map<String, Object> purInRecords = new HashMap<>();
            purInRecords.put("rowno", j);  // 行号
            purInRecords.put("product", product);  // 物料
            purInRecords.put("invExchRate", "1");  // 库存换算率
            purInRecords.put("unitExchangeType", "1");  // 库存换算率换算方式
            String unit = redisPrJson.getStr("unitId");
            purInRecords.put("stockUnitId", unit);  // 库存单位
            purInRecords.put("qty", qty);  // 数量
            purInRecords.put("contactsQuantity", qty);  // 应收数量
            purInRecords.put("subQty", qty);  // 件数
            purInRecords.put("priceQty", qty);  // 记价数量
            purInRecords.put("unitExchangeTypePrice", 0);  // 计价换算率换算方式
            purInRecords.put("invPriceExchRate", 1);  // 计价换算率

            purInRecords.put("oriUnitPrice", taxFreeUnitPrice); // 无税单价
            purInRecords.put("oriTaxUnitPrice", taxFreeUnitPrice); // 含税单价
            purInRecords.put("oriMoney", noTaxSaleAmount);  // 无税金额
            purInRecords.put("oriSum", saleAmount);  // 含税金额
            purInRecords.put("oriTax", taxAmount);  // 税额
            purInRecords.put("natUnitPrice", taxFreeUnitPrice);  // 本币无税单价
            purInRecords.put("natTaxUnitPrice", zb.getBigDecimal("cost_price"));  // 本币含税单价
            purInRecords.put("natMoney", noTaxSaleAmount);  // 本币无税金额
            purInRecords.put("natSum", saleAmount);  // 本币含税金额
            purInRecords.put("costUnitPrice", taxFreeUnitPrice);  // 成本单价
            purInRecords.put("costMoney", noTaxSaleAmount);  // 成本金额
            purInRecords.put("natTax", taxAmount);  // 本币税额

            purInRecords.put("priceUOM", unit);  // 计价单位
            purInRecords.put("taxitems", redisPrJson.getStr("outTaxrate") != null ? redisPrJson.getStr("outTaxrate") : "NL");  // 税目税率
            purInRecords.put("autoCalcCost", false);  // 存货自动计算成本标识
            purInRecords.put("_status", "Insert");
            purInRecords.put("batchno", "旺店通");  // 批次号
            objects.add(purInRecords);
        }
        body.put("purInRecords", objects);
        body.put("resubmitCheckKey", UUID.randomUUID().toString().replace("-", ""));
        //ReSubmitUtil.resubmitCheckKey(body);
        data.put("data", body);
        return data;
    }

    /**
     * @Author Huangwb
     * @Description 查询YS系统租户动态域名信息
     * @Date 2023/10/30 15:45
     **/
    public ReturnT<String> getYsDynamicDomainName(QueryDto ysQueryDto) {
        try {
            String tenantId = ysQueryDto.getTenantId();  // 租户ID
            if (RedisUtils.get(tenantId + ":DynamicDomainName") == null) {
                // 根据租户ID查询动态域名
                JSONObject dynamicDomainName = yonsuiteService.getDynamicDomainName(null, tenantId);
                if (null != dynamicDomainName && !dynamicDomainName.isEmpty()) {
                    // 将动态域名存入Redis
                    RedisUtils.set(tenantId + ":DynamicDomainName", dynamicDomainName, 86400 * 30);
                } else {
                    logger.error("查询租户【{}】动态域名失败，请重试", tenantId);
                    // insertXxlJobLog(null, "0", "租户：【" + tenantId + "】获取动态域名失败，请稍后重试", jobClassType);
                    InsertLogger(null, "0", "获取动态域名失败");
                    return new ReturnT<>(ReturnT.FAIL_CODE, "查询租户【" + tenantId + "】动态域名失败，请重试");
                }
            }
            // 获取Redis中指定租户动态域名
            JSONObject dynamicDomainNameRedis = (JSONObject) RedisUtils.get(tenantId + ":DynamicDomainName");
            ysQueryDto.setGatewayUrl(dynamicDomainNameRedis.getStr("gatewayUrl"));
            ysQueryDto.setTokenUrl(dynamicDomainNameRedis.getStr("tokenUrl"));
            return null;
        } catch (Exception e) {
            return new ReturnT<>(ReturnT.FAIL_CODE, "获取动态域名失败：" + e.getMessage());
        }
    }

    private List<JSONObject> sendWdt(Map<String, Object> map) {
        String apiUrl = "stockin_order_query.php";
        List<JSONObject> resList = new ArrayList<>();
        WdtClient client = new WdtClient(configProperties.getSid(), configProperties.getKey(), configProperties.getSecret(), configProperties.getUrl());
        Integer realityPageNo = 0;
        map.put("page_no", realityPageNo.toString());
        map.put("order_type", 1);
        map.put("page_size", "100");
        if (map.get("stockin_no") == null) {
            map.put("start_time", map.get("Start"));
            map.put("end_time", map.get("End"));
            // map.put("status", 80);//入库单状态 10已取消20编辑中25待价格确认30待审核60待结算80已完成（默认80）
        }
        boolean hasNext = true;
        //总页数
        Integer totalPage = 0;
        //总条数
        Integer total_count = 0;
        while (hasNext) {
            map.put("page_no", realityPageNo.toString());
            String res = null;
            try {
                res = client.execute(apiUrl, map);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            JSONObject saleOutJson = JSONUtil.parseObj(res);
            if ("0".equals(saleOutJson.getStr("code"))) {
                //判断分页
                if (realityPageNo == 0) {
                    total_count = saleOutJson.getInt("total_count", 0);
                    totalPage = total_count % 100 == 0 ? total_count / 100 : total_count / 100 + 1;
                }
                //每页订单列表
                JSONArray orderArray = saleOutJson.getJSONArray("stockin_list");
                if (orderArray.size() > 0) {
                    resList.addAll(JSONUtil.toList(orderArray, JSONObject.class));
                }
                //判断分页
                if (realityPageNo == 0) {
                    total_count = saleOutJson.getInt("total_count", 0);
                    totalPage = total_count % 100 == 0 ? total_count / 100 : total_count / 100 + 1;
                }
                if (totalPage > realityPageNo + 1) {
                    realityPageNo += 1;
                } else {
                    hasNext = false;
                }
            } else {
                InsertLogger(null, "0", "旺店通采购入库接口查询失败" + saleOutJson.getStr("message"));
                break;
            }
        }
        return resList;
    }

    /**
     * @return
     * @Author Huangwb
     * @Description 插入数据库日志信息
     * @Date 10:30 2023/9/14
     * @Param
     **/
    private void InsertLogger(String code, String oneL, String mags) {  // 单据编号、是否成功、详细信息
        try {
            JobLogModel jobLogDTO = new JobLogModel();
            jobLogDTO.setJobClass("HYZM005");
            jobLogDTO.setJobCode(code);
            jobLogDTO.setJobTime(new Date());
            jobLogDTO.setJobResult(oneL);
            jobLogDTO.setJobResultMessage(mags);
            jobLogDTO.setJobLogUser("dxroot");
            jobLogDao.insertJobLog(jobLogDTO);
        } catch (Exception e) {
            logger.error("插入日志错误：" + e.getMessage());
        }
    }

}
